package com.zwjstudy.cachestudy.springcache.redis.config;


import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * ClassName: CacheConfig
 * Description:
 *
 * @Author: 张文俊
 * @Create: 2025-09-19 - 19:30
 * @Version: v1.0
 */

@Configuration
public class CacheConfig {

    /**
     * 配置 RedisCacheManager
     * 关键：自定义序列化方式，避免存储JDK序列化后的二进制数据，改用JSON
     */
    @Bean(name = "userCacheManager",autowireCandidate = false)
    public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {

        // 配置 ObjectMapper 以支持复杂对象和类型信息
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 此项必须配置，以便反序列化时能够识别对象类型
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);

        // 使用 Jackson2JsonRedisSerializer 来序列化 value 值
        Jackson2JsonRedisSerializer<Object> jacksonSerializer = new Jackson2JsonRedisSerializer<>(om,Object.class);


        // 创建默认缓存配置，并设置序列化器
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(30)) // 设置全局默认过期时间（配置文件中更具体设置会覆盖此项）
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) // key: String序列化
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jacksonSerializer)) // value: JSON序列化
                .disableCachingNullValues(); // 默认不缓存null值，可根据业务需要在配置文件中覆盖

        // 使用构建器创建 RedisCacheManager
        return RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(config)
                .build();
    }


    @Bean(name = "companyCacheManager",autowireCandidate = false)
    public RedisCacheManager companyCacheManager(RedisConnectionFactory redisConnectionFactory) {
        // 配置 ObjectMapper 以支持复杂对象和类型信息
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 此项必须配置，以便反序列化时能够识别对象类型
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);

        // 使用 Jackson2JsonRedisSerializer 来序列化 value 值
        Jackson2JsonRedisSerializer<Object> jacksonSerializer = new Jackson2JsonRedisSerializer<>(om,Object.class);


        // 创建默认缓存配置，并设置序列化器
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(10)) // 设置全局默认过期时间（配置文件中更具体设置会覆盖此项）
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) // key: String序列化
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jacksonSerializer)) // value: JSON序列化
                .disableCachingNullValues(); // 默认不缓存null值，可根据业务需要在配置文件中覆盖

        // 使用构建器创建 RedisCacheManager
        return RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(config)
                .build();
    }

}
